package com.authine.cloudpivot.ext.applicationservice.authority;

import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.Exceptions;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.ResourceDto;
import com.authine.cloudpivot.ext.enums.system.ResourceTypeEnum;
import com.authine.cloudpivot.ext.model.ResourceEntity;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.common.util.ObjectMapperUtils;
import com.authine.hermes.app.launcher.service.BOService;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.query.ListBOQuery;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.authine.mvp.app.org.dto.domainvo.DeptOrUserVO;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.authine.hermes.app.launcher.service.ApplicationServiceFoundation.CUSTOM_SERVICE;

/**
 * @ClassName ResourceService
 * @Description: 资源服务
 * @Author fj
 * @Date 2021/9/17
 * @Version V1.0
 **/
@Path("ResourceService")
@Slf4j
public class ResourceService {
    private static final BOService boService = ApplicationContextUtils.getBean(BOService.class);

    /**
     * 获取资源树形列表
     *
     * @param resourceDto 请求参数
     * @return 树形列表
     */
    @Path("getResourceTreeList")
    @POST
    @Operation(summary = "获取资源树形列表", tags = CUSTOM_SERVICE)
    public List<ResourceEntity> getResourceTreeList(@Parameter ResourceDto resourceDto) {
        Assert.notNull(resourceDto.getType(), "请求资源类型不能为空");
        Assert.notNull(resourceDto.getButton(), "是否加载菜单不能为空");
        SingleResponse<BOList> resourceBOList;
        // 如果id不为空，直接通过id查询
        if (!StringUtils.isEmpty(resourceDto.getId())) {
            List<String> ids = Arrays.asList(resourceDto.getId().split(";"));
            resourceBOList = BoServiceUtils.findListByIn(ModelConst.T_RESOURCE, "id", ids);
            if (!resourceBOList.isSuccess()) {
                Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
            }
            log.info("------------------------根据资源id获取资源列表：{}------------------------", JSONObject.toJSONString(resourceBOList));
            if (resourceBOList.getData().getTotal() == 0) {
                return Lists.newArrayList();
            } else {
                return setResourceList(resourceBOList.getData().getData(), false, Lists.newArrayList());
            }
        } else {
            // 只获取应用资源数据
            if ("app".equals(resourceDto.getType())) {
                resourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_RESOURCE, "type", ResourceTypeEnum.APP.getCode());
                if (!resourceBOList.isSuccess()) {
                    Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
                }
                log.info("------------------------获取所有应用资源列表：{}------------------------", JSONObject.toJSONString(resourceBOList));
                if (resourceBOList.getData().getTotal() == 0) {
                    return Lists.newArrayList();
                } else {
                    return setResourceList(resourceBOList.getData().getData(), false, Lists.newArrayList());
                }
            } else if ("all".equals(resourceDto.getType())) {
                // 查询所有数据时是否加载菜单，加载菜单查询全部数据
                if (resourceDto.getButton()) {
                    ListBOQuery listQry = new ListBOQuery();
                    listQry.setPageIndex(-1);
                    listQry.setSchemaCode(ModelConst.T_RESOURCE);
                    resourceBOList = boService.list(listQry);
                } else {
                    // 不加载菜单，查询leaf为false的数据
                    resourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_RESOURCE, "leaf", 0);
                }
                if (!resourceBOList.isSuccess()) {
                    Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
                }
                log.info("------------------------获取所有资源列表：{}------------------------", JSONObject.toJSONString(resourceBOList));
                if (resourceBOList.getData().getTotal() == 0) {
                    return Lists.newArrayList();
                } else {
                    // 获取所有应用资源列表
                    List<Map<String, Object>> appResource = resourceBOList.getData().getData()
                            .stream()
                            .filter(map -> ResourceTypeEnum.APP.getCode().equals(String.valueOf(map.get("type"))))
                            .collect(Collectors.toList());

                    return setResourceList(appResource, true, resourceBOList.getData().getData());
                }
            }
        }
        return Lists.newArrayList();
    }

    /**
     * 构建资源结果
     *
     * @param resourceMap 资源map对象
     * @return 资源实体
     */
    private ResourceEntity buildResourceEntity(Map<String, Object> resourceMap) {
        ResourceEntity resourceEntity = new ResourceEntity();
        resourceEntity.setName(String.valueOf(resourceMap.get("name")));
        resourceEntity.setUrl("");
        resourceEntity.setId(String.valueOf(resourceMap.get("id")));
        resourceEntity.setParentId(resourceMap.get("parent_id") == null ? "" : String.valueOf(resourceMap.get("parent_id")));
        resourceEntity.setType(Objects.requireNonNull(ResourceTypeEnum.get(String.valueOf(resourceMap.get("type")))).getDes());
        resourceEntity.setCss("");
        resourceEntity.setEnabled("1".equals(String.valueOf(resourceMap.get("enabled"))));
        resourceEntity.setCreatedBy(ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(resourceMap.get("createdBy")), DeptOrUserVO.class).getName());
        resourceEntity.setCreatedTime(String.valueOf(resourceMap.get("createdTime")));
        if (resourceMap.get("modifiedBy") == null) {
            resourceEntity.setModifiedBy("");
            resourceEntity.setModifiedTime("");
        } else {
            resourceEntity.setModifiedBy(ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(resourceMap.get("modifiedBy")), DeptOrUserVO.class).getName());
            resourceEntity.setModifiedTime(String.valueOf(resourceMap.get("modifiedTime")));
        }
        return resourceEntity;
    }

    /**
     * 通过父菜单获取所有子菜单
     *
     * @param parentId       父菜单id
     * @param resourceBOList 所有资源列表
     * @return 子菜单列表
     */
    private List<ResourceEntity> getChildrenResource(String parentId, List<Map<String, Object>> resourceBOList) {
        List<Map<String, Object>> resourceListByParentId = resourceBOList.stream()
                .filter(map -> parentId.equals(String.valueOf(map.get("parent_id"))))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(resourceListByParentId)) {
            return null;
        } else {
            return setResourceList(resourceListByParentId, true, resourceBOList);
        }
    }

    /**
     * 设置资源列表数据
     *
     * @param resourceBOList  查询结果数据
     * @param hasChildren     是否包含子菜单
     * @param allResourceList 所有资源列表
     * @return 资源列表
     */
    private List<ResourceEntity> setResourceList(List<Map<String, Object>> resourceBOList, Boolean hasChildren, List<Map<String, Object>> allResourceList) {
        List<ResourceEntity> resourceList = Lists.newArrayList();
        for (Map<String, Object> resourceMap : resourceBOList) {
            ResourceEntity resourceEntity = buildResourceEntity(resourceMap);
            // 根据parent_id查询所有子数据
            if (hasChildren) {
                resourceEntity.setChildren(getChildrenResource(resourceEntity.getId(), allResourceList));
            }
            resourceList.add(resourceEntity);
        }
        return resourceList;
    }
}
